/**
 * 深拷贝开辟一个新的栈，两个对象属性完全相同，但是对应两个不同的地址，修改一个对象的属性，不会改变另一个对象的属性
 * 常见的深拷贝方式有：
 *  _.cloneDeep
 *  Jq的extend
 *  JSON.parse(JSON.stringify())
 *  手写循环递归
 */

function deepClone(obj, hash = new WeakMap()) {

    // 如果是null或者undefined，直接返回, 就不进行拷贝操作
    if(obj == null) {
        return obj;
    }

    if(obj instanceof Date) {
        return new Date(obj);
    }
    if(obj instanceof RegExp) {
        return new RegExp(obj);
    }
    // 可能是对象或者普通的值， 如果是函数的话是不需要深拷贝
    if(typeof(obj) !== 'object') {
        return obj;
    }

    if(hash.get(obj)) {
        return hash.get(obj);
    }

    let cloneObj = new obj.constructor();
    hash.set(obj, cloneObj);
    for(let prop in obj) {
        if(obj.hasOwnProperty(prop)) {
            // 实现一个深拷贝
            cloneObj[prop] = deepClone(obj[prop], hash);
        }
    }
    return cloneObj;
}

let obj = {
    address: {
        province: 'beijing'
    },
    add: ()=>{
        console.log('add');
    }
}

deepClone(obj);


// 方法二：


const deepClone2 = (target, cache = new Map()) => {
    const isObject = (obj) => typeof obj === 'object' && obj !== null
  
    if (isObject(target)) {
      // 解决循环引用
      const cacheTarget = cache.get(target)
      
      if (cacheTarget) {
        return cacheTarget
      }
  
      let cloneTarget = Array.isArray(target) ? [] : {}
  
      cache.set(target, cloneTarget)
  
      for (const key in target) {
        const value = target[ key ] 
        cloneTarget[ key ] = isObject(value) ? deepClone(value, cache) : value
      }
  
      return cloneTarget
    } else {
      return target
    }
  }
  